package com.topisv.tms.service;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.Direction;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.topisv.tms.entity.AlreadyDeductedOut;
import com.topisv.tms.entity.SkuInOutInfo;
import com.topisv.tms.entity.SkuOverInfo;
import com.topisv.tms.entity.WaCountPlan;
import com.topisv.tms.entity.stock.instorage.InstorageInfo;
import com.topisv.tms.entity.stock.instorage.OutstorageInfo;
import com.topisv.tms.repository.AlreadyDeductedOutDao;
import com.topisv.tms.repository.SkuInOutInfoDao;
import com.topisv.tms.repository.stock.instorage.InstorageInfoDao;
import com.topisv.tms.repository.stock.instorage.OutstorageInfoDao;
import com.topisv.tms.service.base.BaseService;
import com.topisv.tms.task.warehouseage.JdbcUtil;

@Component
@Transactional(readOnly = false)
public class WarehouseAgeService extends BaseService {
	static protected Logger log = LoggerFactory.getLogger(WarehouseAgeService.class);
	@Autowired
	private InstorageInfoDao instorageInfoDao;
	@Autowired
	private OutstorageInfoDao outstorageInfoDao;
	@Autowired
	private SkuOverInfoService skuOverInfoService;
	@Autowired
	private AlreadyDeductedOutDao adoDao;
	@Autowired
	private WaCountPlanService wcpService;
	@Autowired
	private SkuInOutInfoDao sioiDao;
	public static void main(String[] args) throws ParseException {
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
		String s = "2015-03-30";
		Date a = format.parse(s);
		Date a1 = new Date(a.getTime()+154 * 24 * 3600 * 1000L);
		System.out.println(format.format(a1));
	}
	@Transactional(propagation=Propagation.REQUIRES_NEW)
	public String goodsAge()
			throws Exception {
		long a = System.currentTimeMillis();
		print("开始计算库龄");
		String msg = "";
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
		SimpleDateFormat formatTime = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss:SSS");
		
		
		List<SkuOverInfo> soiList = null;
//		List<SkuOverInfo> soiOldList = null;
		HashMap<Long,SkuOverInfo> soiOldMap = null;
		List<SkuOverInfo> soiOldDeleteList = null;
		// sku超出库存
		print("获取sku超出库存");
		HashMap<String, ArrayList<HashMap<String, Object>>> overNumMap = new HashMap<String, ArrayList<HashMap<String, Object>>>();
		ArrayList<SkuInOutInfo> sioiList = new ArrayList<SkuInOutInfo>();
		setOverNumMap(overNumMap,sioiList);
		print("获取sku超出库存完成");
		
		print("获取已扣减库存的出库记录");
		List<AlreadyDeductedOut> adoList = new ArrayList<AlreadyDeductedOut>();
		Map<Long,AlreadyDeductedOut> adoMap = new HashMap<Long,AlreadyDeductedOut>();
		
		//跑的天数
		int loopCount = 0 ;
		int overTimeDay = 30;
		Date opeTime = null;
		Date startTime = null;
		Date endTime = null;
		print("开始计算逻辑，一次最多算100天数据,开始循环");
		List<WaCountPlan> backCountWcpList = new ArrayList<WaCountPlan>();
		
		WaCountPlan countWcp = null;
		while (true) {System.out.println("-----------overNumMap:"+overNumMap.size());
			int flag = 1;
			try{
				//一次执行任务最多跑100天
				if(loopCount++==6){
					break;
				}
				print("循环："+loopCount+"次");
				countWcp = null;
				//查询可以当前可以执行的最晚的一天
				List<WaCountPlan>  countWcpList = wcpService.findExecuteRecord();
				if(countWcpList.size()>0){
					countWcp = countWcpList.get(0); 
				}
				//获取的这一天的执行状态
				Date minDate = null;
				if(countWcp == null||StringUtils.isEmpty(countWcp.getCountDate())){
					minDate = instorageInfoDao.loadMinRecode();
					minDate = format.parse(format.format(minDate));
					
					opeTime = minDate;
					opeTime = format.parse(format.format(opeTime));
					
					countWcp = new WaCountPlan();
					countWcp.setCountDate(format.format(opeTime));
					countWcp.setStatus("doing");
					wcpService.save(countWcp);
					
				}else if("doing".equals(countWcp.getStatus())) {
					msg = "doing";
					break;// "doing";
				}else if("finish".equals(countWcp.getStatus())||"end".equals(countWcp.getStatus())) {
					if((format.parse(format.format(new Date())).getTime() - format.parse(countWcp.getCountDate()).getTime() ) <= 1 * 24 * 3600 * 1000L){
						msg = "finish";
						break;
					}
					opeTime = new Date(format.parse(countWcp.getCountDate()).getTime() +  1 * 24 * 3600 * 1000L);
					
					countWcp = new WaCountPlan();
					countWcp.setCountDate(format.format(opeTime));
					countWcp.setStatus("doing");
					wcpService.save(countWcp);
				}else {//new
					countWcp.setStatus("doing");
					wcpService.save(countWcp);
				}
				backCountWcpList.add(countWcp);
				
//				startTime = new Date(opeTime.getTime()-30 * 24 * 3600 * 1000L);
//				endTime = startTime;
				
				print("从sku超库龄信息表中查处还没有结束库龄超期的数据。");
				//从sku超库龄信息表中查处还没有结束库龄超期的数据。
//				soiList = skuOverInfoService.findByEndFlag(false);
//				print("从sku超库龄信息表中查处还没有结束库龄超期的数据。");
				soiList = JdbcUtil.findByEndFlag(false);
//				print("从sku超库龄信息表中查处还没有结束库龄超期的数据。3");
//				soiOldList = new ArrayList<SkuOverInfo>();
				soiOldMap = new HashMap<Long,SkuOverInfo>();
				print("查询完毕并复制一份.");
				SkuOverInfo soiOld = null;
				for (SkuOverInfo soi : soiList) {
					soiOld = new SkuOverInfo();
					soiOld.setCustomerCode(soi.getCustomerCode());
					soiOld.setEndFlag(soi.getEndFlag());
					soiOld.setEndTime(soi.getEndTime());
					soiOld.setId(soi.getId());
					soiOld.setOpeTime(soi.getOpeTime());
					soiOld.setOverDay(soi.getOverDay());
					soiOld.setOverNum(soi.getOverNum());
					soiOld.setSku(soi.getSku());
					soiOld.setStartTime(soi.getStartTime());
					soiOld.setWarehouseCode(soi.getWarehouseCode());
//					soiOldList.add(soiOld);
					soiOldMap.put(soi.getId(), soiOld);
				}
				startTime = new Date(opeTime.getTime() - (overTimeDay+1) * 24 * 3600 * 1000L);
				endTime = new Date(startTime.getTime() + 1 * 24 * 3600 * 1000L);
	
				print(format.format(opeTime) + "|" + format.format(startTime) + "|" + format.format(endTime));
	
				print("开始查询instorageInfo");
				List<InstorageInfo> iiList = instorageInfoDao.load30DayAfterRecode(formatTime.parse(format.format(startTime)+ " 00:00:00:001"),
								formatTime.parse(format.format(endTime)	+ " 00:00:00:001"));
				print("查询instorageInfo完毕");
				
				print("开始查询outstorageInfo");
				List<OutstorageInfo> oiList = outstorageInfoDao
						.loadBy30DayWithinRecord(formatTime.parse(format.format(startTime)+ " 00:00:00:001"),
								formatTime.parse(format.format(opeTime)	+ " 00:00:00:001"));
				print("查询outstorageInfo完毕");
				
				//将新的入库信息加入的库龄计算map中
				for (InstorageInfo ii : iiList) {
					String warehouseCode = ii.getWarehouseCode();
					String customerCode = ii.getCustomerCode();
					String sku = ii.getSku();
					String key = warehouseCode + ":" + customerCode + ":" + sku;
	
					ArrayList<HashMap<String, Object>> skuList = null;
					if (!overNumMap.containsKey(key)) {
						skuList = new ArrayList<HashMap<String, Object>>();
						HashMap<String, Object> daySkuMap = new HashMap<String, Object>();
						daySkuMap.put("opeTime", format.format(startTime));
						daySkuMap.put("num", ii.getNum());
						daySkuMap.put("yichuNum", 0);
						skuList.add(daySkuMap);
					} else {
						skuList = overNumMap.get(key);
						boolean result= false;
						for(HashMap<String, Object> daySkuMap :skuList){
							if (daySkuMap.get("opeTime").equals(format.format(ii.getOpeTime()))) {
								daySkuMap.put("num", ((Integer) daySkuMap.get("num")) + ii.getNum());
								daySkuMap.put("yichuNum", 0);
								result = true;
								break;
							}
						}
						if(!result){
							HashMap<String, Object>  daySkuMap = new HashMap<String, Object>();
							daySkuMap.put("opeTime", format.format(startTime));
							daySkuMap.put("num", ii.getNum());
							daySkuMap.put("yichuNum", 0);
							skuList.add(daySkuMap);
						}
					}
					overNumMap.put(key, skuList);
				}
				
				print("开始循环扣减库龄");
				ArrayList<Long> adoIdList = new ArrayList<Long>();
				for (OutstorageInfo oi : oiList) {
					adoIdList.add(oi.getId());
				}
				print("adoIdList finish");
				List<AlreadyDeductedOut> adoTempList = adoDao.findByOutinstorageIds(
						formatTime.parse(format.format(startTime)
								+ " 00:00:00:001"),
						formatTime.parse(format.format(opeTime)
								+ " 00:00:00:001"));
				for (AlreadyDeductedOut ado : adoTempList) {
					if(!adoMap.containsKey(ado.getOutinstorageId())){
						adoMap.put(ado.getOutinstorageId(), ado);
					}
				}
				for (OutstorageInfo oi : oiList) {
					String warehouseCode = oi.getWarehouseCode();
					String customerCode = oi.getCustomerCode();
					String sku = oi.getSku();
					String key = warehouseCode + ":" + customerCode + ":" + sku;
					if (overNumMap.containsKey(key)) {
						ArrayList<HashMap<String, Object>> skuList = overNumMap.get(key);
						Collections.sort(skuList,
								new Comparator<HashMap<String, Object>>() {
									@Override
									public int compare(
											HashMap<String, Object> o1,
											HashMap<String, Object> o2) {
										return ((String) o1.get("opeTime")).compareTo((String)o2.get("opeTime"));
									}
								});
						for (HashMap<String, Object> daySkuMap : skuList) {
							if ((Integer) daySkuMap.get("num") > (Integer) daySkuMap.get("yichuNum")) {
								AlreadyDeductedOut ado = adoMap.get(oi.getId());
								int alreadyDeductedNum = ado==null?0:ado.getAlreadyDeductedNum();
								int nengkouNum = oi.getNum() - alreadyDeductedNum;
								int xukouNum = (Integer) daySkuMap.get("num")
										- (Integer) daySkuMap.get("yichuNum");
								int bencikouNum = 0;
								if (nengkouNum >= xukouNum) {
									bencikouNum = xukouNum;
								} else {
									bencikouNum = nengkouNum;
								}
	
								daySkuMap.put("yichuNum",(Integer) daySkuMap.get("yichuNum") + bencikouNum);
								
								if(ado == null){
									ado = new AlreadyDeductedOut();
									ado.setOutinstorageId(oi.getId());
									ado.setOutinstorageNum(oi.getNum());
									ado.setAlreadyDeductedNum(alreadyDeductedNum + bencikouNum);
									adoMap.put(oi.getId(), ado);
								}else {
									ado.setAlreadyDeductedNum(alreadyDeductedNum + bencikouNum);
								}
							}
						}
					}
				}
				print("扣减库龄完成");
				print("将扣减完成的数据更新到sku库龄超期信息表中");
				ArrayList<HashMap<String, Object>> skuList = null;
				
				HashMap<String,String> soiMap = new HashMap<String,String>();
				for (int j = 0; j < soiList.size(); j++) {
					SkuOverInfo soi = soiList.get(j);
					String customerCode = soi.getCustomerCode();
					String warehouseCode = soi.getWarehouseCode();
					String sku = soi.getSku();
					String soiOpeTime = format.format(soi.getOpeTime());
					String key = warehouseCode+":"+customerCode+":"+sku;
					if(!soi.getEndFlag()){
						soiMap.put(key, j+":"+soiOpeTime);
					}
				}
				
				for(Map.Entry<String, ArrayList<HashMap<String, Object>>> entry: overNumMap.entrySet()) {
					String key = entry.getKey();
					String warehouseCode = key.split(":")[0];
					String customerCode = key.split(":")[1];
					String sku = key.split(":")[2];
					
					skuList = entry.getValue();
					boolean result = false;
					for (int i = 0; i < skuList.size(); i++) {
						HashMap<String, Object> daySkuMap = skuList.get(i);
						String mapOpeTime = (String) daySkuMap.get("opeTime");
						int num = (Integer) daySkuMap.get("num");
						int yichuNum = (Integer) daySkuMap.get("yichuNum");
						
						if(soiMap.containsKey(key)){
							String value = soiMap.get(key);
							Integer soiIndex = Integer.parseInt(value.split(":")[0]);
							String soiOpeTime = value.split(":")[1];
							if(mapOpeTime.equals(soiOpeTime)){
								result=true;
								SkuOverInfo soi = soiList.get(soiIndex);
								if(!soi.getEndFlag()){
									if (num > yichuNum) {
										if(num - yichuNum == soi.getOverNum()){
											soi.setEndTime(new Date(opeTime.getTime()-1 * 24 * 3600 * 1000L));
											int overDay = (int)((soi.getEndTime().getTime() - soi.getStartTime().getTime()) / (1 * 24 * 3600 * 1000L) + 1);
											soi.setOverDay(overDay);
										} else {
											soi.setEndTime(new Date(opeTime.getTime()-2 * 24 * 3600 * 1000L));
											int overDay = (int)((soi.getEndTime().getTime() - soi.getStartTime().getTime()) / (1 * 24 * 3600 * 1000L) + 1);
											soi.setOverDay(overDay);
											soi.setEndFlag(true);
											
											SkuOverInfo soiNew = new SkuOverInfo();
											soiNew.setWarehouseCode(warehouseCode);
											soiNew.setCustomerCode(customerCode);
											soiNew.setSku(sku);
											soiNew.setOverNum(num - yichuNum);
											soiNew.setOpeTime(soi.getOpeTime());
											soiNew.setStartTime(new Date(opeTime.getTime()-1 * 24 * 3600 * 1000L));
											soiNew.setEndTime(new Date(opeTime.getTime()-1 * 24 * 3600 * 1000L));
											soiNew.setOverDay(1);
											soiNew.setEndFlag(false);
											soiList.add(soiNew);
											soiMap.put(key, soiList.size()-1+":"+format.format(soiNew.getOpeTime()));
										}
									} else {
										soi.setEndFlag(true);
										soi.setEndTime(new Date(opeTime.getTime()-1 * 24 * 3600 * 1000L));
										int overDay = (int)((soi.getEndTime().getTime() - soi.getStartTime().getTime()) / (1 * 24 * 3600 * 1000L) + 1);
										soi.setOverDay(overDay);
									}
								}
							}
						}
						if (!result) {
							if (num > yichuNum) {
								SkuOverInfo soiNew = new SkuOverInfo();
								soiNew.setWarehouseCode(warehouseCode);
								soiNew.setCustomerCode(customerCode);
								soiNew.setSku(sku);
								soiNew.setOverNum(num - yichuNum);
								soiNew.setOpeTime(startTime);
								soiNew.setStartTime(new Date(opeTime.getTime()-1 * 24 * 3600 * 1000L));
								soiNew.setEndTime(new Date(opeTime.getTime()-1 * 24 * 3600 * 1000L));
								soiNew.setOverDay(1);
								soiNew.setEndFlag(false);
								soiList.add(soiNew);
								soiMap.put(key, soiList.size()-1+":"+format.format(soiNew.getOpeTime()));
							}
						}
						
					}
				}

				//计算下一天的库龄
				opeTime = new Date(opeTime.getTime() + 1 * 24 * 3600 * 1000L);
				
				print("查找不需要保存的数据");
				soiOldDeleteList = new ArrayList<SkuOverInfo>();
				for (int q = soiList.size()-1 ; q >= 0;q--) {
					SkuOverInfo soi = soiList.get(q);
					SkuOverInfo soiOld1 = soiOldMap.get(soi.getId());
					if(soiOld1 != null&&soi.getId()!=null){
						if(soiOld1.getId()!=null&&soiOld1.getId().equals(soi.getId())&&
								soiOld1.getCustomerCode()!=null&&soiOld1.getCustomerCode().equals(soiOld1.getCustomerCode())&&
								soiOld1.getEndFlag() == soi.getEndFlag()&&
								soiOld1.getEndTime()!=null&&soiOld1.getEndTime().equals(soi.getEndTime())&&
								soiOld1.getOpeTime()!=null&&soiOld1.getOpeTime().equals(soi.getOpeTime())&&
								soiOld1.getOverDay()==(soi.getOverDay())&&
								soiOld1.getOverNum()==(soi.getOverNum())&&
								soiOld1.getSku()!=null&&soiOld1.getSku().equals(soi.getSku())&&
								soiOld1.getStartTime()!=null&&soiOld1.getStartTime().equals(soi.getStartTime())&&
								soiOld1.getWarehouseCode()!=null&&soiOld1.getWarehouseCode().equals(soi.getWarehouseCode())
								){
//							soiOldDeleteList.add(soi);
							soiList.remove(q);
						}
					}
				}
//				soiList.removeAll(soiOldDeleteList);
				print("删除了"+soiOldDeleteList.size()+"条不需要保存的数据,还要保存"+soiList.size()+"条数据.");
				
//				soiOldList.clear();
//				soiOldDeleteList.clear();
				
				print("更新sku超期信息表");
				JdbcUtil.saveSkuOverInfo(soiList);
//				skuOverInfoService.save(soiList);
				++flag;
				print("更新库龄计算任务状态finish");
				countWcp.setStatus("finish");
				wcpService.save(countWcp);
				++flag;
			}catch(Exception e){
				print("保存失败:"+e);
				//计算出错回滚操作
//				if(flag == 1){
//				}else if(flag == 2) {
//					for(WaCountPlan wcp:backCountWcpList){
//						if(wcp!=null){
//							wcp.setStatus("new");
//						}
//					}
//					wcpService.save(backCountWcpList);
//				}else if(flag == 3) {
//					
//				}
				throw new Exception("保存失败，数据回滚"+e);
			}
		}
		
		print("将已扣减库存的出库单记录保存");
		Set<Long> adoKeySet = adoMap.keySet();
		Iterator<Long> keyIterator = adoKeySet.iterator();
		while(keyIterator.hasNext()) {
			Long key = keyIterator.next();
			AlreadyDeductedOut ado = (AlreadyDeductedOut)adoMap.get(key);
			adoList.add(ado);
		}
		adoDao.save(adoList);
		print("已扣减库存的出库单记录保存成功");
		
		sioiList = new ArrayList<SkuInOutInfo>();
		//删除所有超期信息。。。
		sioiDao.deleteAll();
		
		ArrayList<HashMap<String, Object>> skuList = null;
		Set<String> keySet = overNumMap.keySet();
		Iterator<String> iterator = keySet.iterator();
		while (iterator.hasNext()) {
			String key = iterator.next();
			String warehouseCode = key.split(":")[0];
			String customerCode = key.split(":")[1];
			String sku = key.split(":")[2];

			skuList = overNumMap.get(key);
			for (int i = 0; i < skuList.size(); i++) {
				HashMap<String, Object> daySkuMap = skuList.get(i);
				String mapOpeTime = (String) daySkuMap.get("opeTime");
				int num = (Integer) daySkuMap.get("num");
				int yichuNum = (Integer) daySkuMap.get("yichuNum");
				if(num != yichuNum){
					SkuInOutInfo sioi = new SkuInOutInfo();
					sioi.setWarehouseCode(warehouseCode);
					sioi.setCustomerCode(customerCode);
					sioi.setSku(sku);
					sioi.setOpeTime(mapOpeTime);
					sioi.setInNum(num);
					sioi.setOutNum(yichuNum);
					sioiList.add(sioi);
				}
			}
		}
		//将未计算完成的数据缓存下来，用作一下次计算
		sioiDao.save(sioiList);
		
		
		//计算计划更新为计算完成
		for(WaCountPlan wcp:backCountWcpList){
			if(wcp!=null){
				wcp.setStatus("end");
			}
		}
		wcpService.save(backCountWcpList);
				
		print("库龄计算完毕");
		print("耗时:"+((System.currentTimeMillis() - a)/1000)+" M");
		//保存
		return msg;
	}
	
	public void setOverNumMap(HashMap<String, ArrayList<HashMap<String, Object>>> overNumMap,
			ArrayList<SkuInOutInfo> sioiList){
		Sort sort = new Sort(Direction.DESC, "opeTime");
		sioiList = (ArrayList<SkuInOutInfo>) sioiDao.findAll(sort);
		
		for(SkuInOutInfo sioi:sioiList){
			String warehouseCode = sioi.getWarehouseCode();
			String customerCode = sioi.getCustomerCode();
			String sku = sioi.getSku();
			String key = warehouseCode + ":" + customerCode + ":" + sku;
			
			ArrayList<HashMap<String, Object>> skuList = null;
			if (!overNumMap.containsKey(key)) {
				skuList = new ArrayList<HashMap<String, Object>>();
				HashMap<String, Object> daySkuMap = new HashMap<String, Object>();
				daySkuMap.put("opeTime", sioi.getOpeTime());
				daySkuMap.put("num", sioi.getInNum());
				daySkuMap.put("yichuNum", sioi.getOutNum());
				skuList.add(daySkuMap);
			} else {
				skuList = overNumMap.get(key);
				HashMap<String, Object> daySkuMap = new HashMap<String, Object>();
				daySkuMap.put("opeTime", sioi.getOpeTime());
				daySkuMap.put("num", sioi.getInNum());
				daySkuMap.put("yichuNum", sioi.getOutNum());
				skuList.add(daySkuMap);
			}
			overNumMap.put(key, skuList);
		}
	}
	
	public static void print(String str){
		SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
		String date = format.format(new Date());
		System.out.println(date+":"+str);
		log.info(date+":"+str);
	}
	
}
